using Magiq.Databases;
using Magiq.Tests.Support;
using NUnit.Framework;

namespace Magiq.Tests
{
    [TestFixture]
    public class SelectStatementParserTests
    {
        private readonly SelectStatementParser parser = new SelectStatementParser();

        [Test]
        public void ShouldSplitCommaDelimitedValues()
        {
            var select = parser.Parse("select bla,ble,bli from xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("ble"));
            select[2].Should(Be.EqualTo("bli"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldParseStatementWithoutWhere()
        {
            var select = parser.Parse("select bla,ble,bli");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("ble"));
            select[2].Should(Be.EqualTo("bli"));
            select.From.Should(Be.Empty);
        }

        [Test]
        public void ShouldNotRemoveFromWordUsedAsValueExpression()
        {
            var select = parser.Parse("select bla,[from],(bli as from) from xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("[from]"));
            select[2].Should(Be.EqualTo("(bli as from)"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldRemoveNewLines()
        {
            var select = parser.Parse("select bla,ble,bli\r\nfrom xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("ble"));
            select[2].Should(Be.EqualTo("bli"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }
        [Test]
        public void ShouldParseUpperCaseExpressions()
        {
            var select = parser.Parse("SELECT BLA,ble AS XX,bli FROM xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("ble"));
            select[2].Should(Be.EqualTo("bli"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldRemoveAliases()
        {
            var select = parser.Parse("select bla lala,ble as lala,(bli) la,(ble,(bla) as lolo) [lala] from xxxxx");
            select.Should(Have.Length(4));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("ble"));
            select[2].Should(Be.EqualTo("(bli)"));
            select[3].Should(Be.EqualTo("(ble,(bla) as lolo)"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldNotTakeOperationAsAliases()
        {
            var select = parser.Parse("select bla + ble, bla - ble from xxxxx");
            select.Should(Have.Length(2));
            select[0].Should(Be.EqualTo("bla + ble"));
            select[1].Should(Be.EqualTo("bla - ble"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldNotRemoveAsWordInsideParenthesis()
        {
            var select = parser.Parse("select bla,(ble as lala),bli from xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("(ble as lala)"));
            select[2].Should(Be.EqualTo("bli"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldSupportSeveralSpaces()
        {
            var select = parser.Parse(" select   bla  +    bla,  (ble   as lala)   , bli   la   from    xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla  +    bla"));
            select[1].Should(Be.EqualTo("(ble   as lala)"));
            select[2].Should(Be.EqualTo("bli"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }


        [Test]
        public void ShouldNotSplitACommaUsedInsideParenthesis()
        {
            var select = parser.Parse("select bla,(ble,bli),blo from xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("(ble,bli)"));
            select[2].Should(Be.EqualTo("blo"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldNotSplitACommaUsedInsideSquareParenthesis()
        {
            var select = parser.Parse("select bla,[ble,bli] from xxxxx");
            select.Should(Have.Length(2));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("[ble,bli]"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldSupportDeepParenthesisUsage()
        {
            var select = parser.Parse("select bla,((ble,bli),blo),blu from xxxxx");
            select.Should(Have.Length(3));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("((ble,bli),blo)"));
            select[2].Should(Be.EqualTo("blu"));
            select.From.Should(Be.EqualTo("xxxxx"));
        }

        [Test]
        public void ShouldNotSplitACommaUsedInsideQuotationMarks()
        {
            var select = parser.Parse("select bla,\"ble,bli\" from xxxxx");
            select.Should(Have.Length(2));
            select[0].Should(Be.EqualTo("bla"));
            select[1].Should(Be.EqualTo("\"ble,bli\""));
            select.From.Should(Be.EqualTo("xxxxx"));
        }
    }
}